package edu.ptu.acl.filter;

import com.google.common.collect.Sets;
import edu.ptu.acl.common.AdminValidate;
import edu.ptu.acl.common.MyConstants;
import edu.ptu.acl.common.RequestHolder;
import edu.ptu.acl.entity.Acl;
import edu.ptu.acl.service.IAclService;
import edu.ptu.acl.service.impl.AclServiceImpl;
import edu.ptu.acl.utils.ApplicationContextHelper;
import edu.ptu.acl.utils.ResponseUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.ApplicationContext;

import javax.annotation.Resource;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class AclControlFilter implements Filter {

    private static Set<String> blankUrlRegexSet = Sets.newConcurrentHashSet();

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // add blankUrl
        blankUrlRegexSet.add("/login/.*/.*");
        blankUrlRegexSet.add("/getInfo");
        blankUrlRegexSet.add("/logout");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //获取url
        HttpServletRequest req = (HttpServletRequest) servletRequest;
        HttpServletResponse resp = (HttpServletResponse) servletResponse;

        String currentUrl = req.getServletPath();

        // 放行白名单
        for (String blankUrl : blankUrlRegexSet) {
            if (Pattern.matches(blankUrl,currentUrl)) {
                filterChain.doFilter(servletRequest,servletResponse);
                return;
            }
        }

        // admin拥有所有权限，直接放行
        if (AdminValidate.isAdmin()) {
            filterChain.doFilter(servletRequest,servletResponse);
            return;
        }

        // 得到当前用户拥有的接口权限
        // 全拿出来在后端做正则，或则在数据库做正则，此处我取出该用户的所有权限
        AclServiceImpl aclService = ApplicationContextHelper.popBean(AclServiceImpl.class);
        List<Acl> currentUserAclList = aclService.getCurrentUserAclList();

        if (CollectionUtils.isEmpty(currentUserAclList)){
            // 用户权限列表为空，返回校验失败
            ResponseUtils.flushFaild(resp,MyConstants.ResultCode.NO_AUTH);
            return;
        }

        // 拿到用户拥有的权限url
        Set<String> currentUserUrl = currentUserAclList.stream()
                .filter(acl -> StringUtils.equals(acl.getType(), MyConstants.AclType.ACL.getId()))// 过滤按钮和组件
                .filter(acl -> StringUtils.equals(acl.getStatus(),MyConstants.AclStatus.NORMAL.getId()))// 过滤冻结权限
                .map(Acl::getUrl).collect(Collectors.toSet());

        if (CollectionUtils.isEmpty(currentUserUrl)){
            // 没有任何接口权限,校验失败
            ResponseUtils.flushFaild(resp,MyConstants.ResultCode.NO_AUTH);
            return;
        }

        // 正则校验
        // 规则：只要有一个权限点有权限，那么我们就认为有访问权限
        for (String url : currentUserUrl) {
            if (Pattern.matches(url,currentUrl)){
                // 校验通过
                filterChain.doFilter(servletRequest,servletResponse);
                return;
            }
        }

        // 校验失败
        ResponseUtils.flushFaild(resp,MyConstants.ResultCode.NO_AUTH);
        return;
    }

    @Override
    public void destroy() {

    }
}
